<template>
	<view class="tech-detail">
		<!-- 导航栏 -->
		<nav-bar></nav-bar>
		<!-- 未选择提示 -->
		<view class="unselected-tips"
			v-if="showUnselectedTips && (!selectedService || !selectedDate || !selectedTime || !selectedAddress)">
			<view class="tips-item" v-if="!selectedService" @tap="scrollToService">
				<text class="icon">●</text>
				<text>选择服务项目</text>
				<text class="jump-text">点击跳转</text>
			</view>
			<view class="tips-item" v-if="!selectedDate || !selectedTime" @tap="scrollToTime">
				<text class="icon">●</text>
				<text>选择服务时间</text>
				<text class="jump-text">点击跳转</text>
			</view>
			<view class="tips-item" v-if="!selectedAddress" @tap="scrollToAddress">
				<text class="icon">●</text>
				<text>选择服务地址</text>
				<text class="jump-text">点击跳转</text>
			</view>
		</view>
		<!-- 技师基本信息 -->
		<view class="tech-info">
			<image class="avatar" :src="techInfo.avatar" mode="aspectFill"></image>
			<view class="info">
				<text class="name">{{ techInfo.name }}</text>
				<view class="rating">
					<text class="score">评分 {{ techInfo.score }}</text>
					<text class="orders">接单 {{ techInfo.orders }}单</text>
				</view>
				<text class="desc">{{ techInfo.title }}</text>
			</view>
			<view class="info-icon">ⓘ</view>
		</view>
		<!-- 技师位置信息 -->
		<view class="location-info">
			<view class="map-container">
				<map class="map" :latitude="techInfo.latitude" :longitude="techInfo.longitude" :markers="markers"
					:polyline="polyline" :scale="mapScale" show-location></map>
			</view>
			<view class="distance-info">
				<text>距您{{ distance }}km</text>
				<text>预计{{ arrivalTime }}分钟到达</text>
			</view>
		</view>
		<!-- 服务项目列表 -->
		<view class="service-list">
			<view class="module-title">
				<text>服务项目</text>
				<text class="scroll-hint">可滚动查看更多</text>
			</view>
			<scroll-view scroll-y :show-scrollbar="true" class="service-scroll" :enhanced="true"
				:always-show-scrollbar="true">
				<view class="service-item" v-for="service in services" :key="service.id"
					:class="{ active: selectedService === service.id }" @tap="selectService(service)">
					<image class="service-image" :src="service.img || '/static/default-service.jpg'" mode="aspectFill">
					</image>
					<view class="service-content">
						<view class="service-info">
							<text class="name">{{ service.name }}</text>
							<text class="duration">{{ service.duration }}分钟</text>
						</view>
						<view class="price-info">
							<text class="price">￥{{ service.price }}</text>
							<text class="original-price">￥{{ service.originalPrice }}</text>
						</view>
					</view>
				</view>
			</scroll-view>
		</view>
		<!-- 时间选择 -->
		<view class="time-select">
			<view class="module-title">
				<text>选择时间</text>
				<text class="scroll-hint">可滚动查看更多</text>
			</view>
			<view class="date-list">
				<view class="date-item" v-for="date in availableDates" :key="date.value"
					:class="{ active: selectedDate === date.value }" @tap="fetchAvailableTimes(date)">
					<text class="day">{{ date.day }}</text>
					<text class="date">{{ date.date }}</text>
				</view>
			</view>
			<scroll-view scroll-y :show-scrollbar="true" class="time-list" :enhanced="true"
				:always-show-scrollbar="true">
				<view class="time-grid">
					<view class="time-item" v-for="time in availableTimes" :key="time.value" :class="{ 
							active: selectedTime === time.value,
							disabled: time.disabled
						}" @tap="selectTime(time)">
						<text class="time-text">{{ time.label }}</text>
						<text class="duration-text" v-if="currentService && currentService.duration">
							{{ getEndTimeInfo(time.value) }}
							<text v-if="currentService.duration">({{ currentService.duration }}分钟)</text>
						</text>
					</view>
				</view>
			</scroll-view>
		</view>
		<!-- 地址选择 -->
		<view class="address-select">
			<view class="module-title">地址选择</view>
			<view class="address-input" @tap="toggleAddressList">
				<view class="input-content" :class="{ placeholder: !selectedAddress }">
					{{ selectedAddress.fullAddress || '请选择服务地址' }}
				</view>
				<text class="arrow">></text>
			</view>
		</view>
		<!-- 交通费用显示 -->
		<view class="transport-fee">
			<view class="module-title">交通费用</view>
			<view class="fee-display">
				<text class="fee-label">交通费用</text>
				<text class="fee-amount">￥{{ transportFee }}</text>
			</view>
		</view>
		<!-- 地址选择弹出层 -->
		<view class="address-popup" :class="{ show: showAddressList }">
			<view class="popup-header">
				<text class="title">选择地址</text>
				<view class="header-right">
					<text class="manage" @tap="goToAddressManage">地址管理</text>
					<text class="close" @tap="toggleAddressList">✕</text>
				</view>
			</view>
			<view class="address-list">
				<view class="address-item" v-for="address in sortedAddressList" :key="address.id"
					:class="{ active: selectedAddress === address.address }" @tap="selectAddress(address)">
					<view class="address-info">
						<view class="left-info">
							<text class="name">{{ address.recipientName }}</text>
							<text class="phone">{{ address.recipientPhone }}</text>
						</view>
						<view class="right-info">
							<text v-if="address.tag" class="tag">{{ address.tag }}</text>
							<text v-if="address.isDefault === 1" class="default-tag">默认</text>
						</view>
					</view>
					<text class="address">{{ address.fullAddress }}</text>
					<text class="select-icon" v-if="selectedAddress === address.fullAddress">✓</text>
				</view>
			</view>
		</view>
		<view class="coupon-section" v-if="selectedService">
			<view class="module-title">优惠券</view>
			<view class="coupon-list">
				<view class="coupon-item" v-for="coupon in availableCoupons" :key="coupon.id"
					:class="{ active: selectedCoupon && selectedCoupon.id === coupon.id }" @tap="selectCoupon(coupon)">
					<view class="coupon-info">
						<view class="coupon-name">{{ coupon.coupons.title }}</view>
						<view class="coupon-desc">{{ coupon.coupons.limitDesc }}</view>
						<view class="coupon-validity">有效期至：{{ coupon.expireTime }}</view>
					</view>
					<view class="coupon-amount">
						<text class="amount">￥{{ coupon.coupons.amount }}</text>
						<text class="condition" v-if="coupon.coupons.minAmount">满{{ coupon.coupons.minAmount }}可用</text>
					</view>
				</view>
				<view class="no-coupon" v-if="availableCoupons.length === 0">
					暂无可用优惠券
				</view>
			</view>
		</view>
		<view class="member-card-section" v-if="selectedService">
			<view class="module-title">会员卡</view>
			<view class="member-card-list">
				<view class="member-card-item" v-for="card in availableMemberCards" :key="card.id" :class="{ 
						active: selectedMemberCard && selectedMemberCard.id === card.id,
					}" @tap="selectMemberCard(card)">
					<view class="card-info">
						<view class="card-name">
							{{ card.memberCard.cardName }}
						</view>
						<view v-if="card.memberCard.cardType === 1" class="card-desc">
							余额：{{ card.balance }}元
						</view>
						<view v-if="card.memberCard.cardType === 2" class="card-desc">
							剩余次数：{{ card.remainingTimes }}次
						</view>
						<view class="card-validity">
							有效期至：{{ card.memberCard.expireTime }}</view>
					</view>
					<view class="card-action">
						<text class="action-text">
							{{ selectedMemberCard && selectedMemberCard.id === card.id ? '已选择' : '选择' }}
						</text>
					</view>
				</view>
				<view class="no-card" v-if="availableMemberCards.length === 0">
					暂无可用会员卡
				</view>
			</view>
		</view>
		<!-- 附赠项目列表 -->
		<view class="gift-service-list" v-if="selectedMemberCard && giftProject && giftProject.status === true">
			<view class="module-title">附赠项目</view>
			<text class="module-title">- 剩余次数：{{ giftProject.num }}</text>
			<text class="module-title">- 有效期至: {{ giftProject.expireTime }}</text>
			<view class="gift-item" v-for="gift in giftProject.list" :key="gift.id" :class="{ 
					active: selectedGiftId === gift.id,
				}" @tap="selectGiftService(gift)">
				<view class="gift-info">
					<text class="name">
						{{ gift.projectName }}
					</text>
				</view>
				<view class="gift-action">
					<text class="action-text">
						{{ selectedGiftId === gift.id ? '已选择' : '选择' }}
					</text>
				</view>
			</view>
		</view>
		<!-- 备注信息 -->
		<view class="remark-section">
			<view class="module-title">备注信息</view>
			<view class="remark-input">
				<textarea v-model="remark" placeholder="请输入备注信息（选填）" maxlength="200"
					:show-confirm-bar="false"></textarea>
				<text class="word-count">{{ remark.length }}/200</text>
			</view>
		</view>
		<!-- 遮罩层 -->
		<view class="mask" v-if="showAddressList" @tap="toggleAddressList"></view>
		<view style="position: fixed;left: 0;right: 0;bottom: 5%;">
			<uni-notice-bar show-icon scrollable
				text="感谢您选择我们的服务，出于对顾客的权益保护，本平台禁止任何线下交易，顾客和技师之间只使用平台虚拟号进行线上联系，一旦发现技师违反平台规定向顾客索要联系方式或进行私下交易，凭相关证据（视频或照片或语音），顾客可获得平台免单及现金奖励。" />
		</view>
		<!-- 结算模块 -->
		<view class="settlement">
			<view class="price-info">
				<text class="label">总计</text>
				<text class="price">￥{{ totalPrice }}</text>
			</view>
			<button class="submit-btn" @tap="showConfirmDialog" :class="{ 'disabled': isSubmitting || isTechnician }"
				:style="isTechnician ? 'background: #CCCCCC; box-shadow: none;' : ''">
				{{ isSubmitting ? '提交中...' : (isTechnician ? '技师账号不可预约' : '立即预约') }}
			</button>
		</view>
		<!-- 小型确认弹窗 -->
		<view class="mini-confirm-dialog" v-if="showMiniConfirm">
			<view class="dialog-content">
				<view class="dialog-title">确认预约</view>
				<view class="dialog-text">是否确认预约该服务？</view>
				<view class="dialog-price">￥{{totalPrice}}</view>
				<view class="dialog-buttons">
					<button class="cancel-btn" @tap="cancelConfirm">取消</button>
					<button class="confirm-btn" @tap="submitOrder">确认</button>
				</view>
			</view>
			<view class="dialog-mask" @tap="cancelConfirm"></view>
		</view>
	</view>
</template>

<script>
import NavBar from '@/components/nav-bar/nav-bar.vue';
import {request} from '@/utils/request.js';

export default {
		components: {
			NavBar
		},
		data() {
			return {
				giftProject: null,
				isTechnician: false, // 添加技师标识
				userLocation: {
					latitude: 0,
					longitude: 0
				},
				techInfo: {
					id: '',
					name: '推拿专家',
					avatar: '/static/images/default-avatar.png',
					score: 0,
					orders: 0,
					title: '专业技师',
					latitude: 0,
					longitude: 0
				},
				distance: 0,
				arrivalTime: 0,
				transportFee: 0, // 固定交通费用
				services: [],
				markers: [],
				mapScale: 10, // 添加地图缩放级别
				// 添加会员卡相关数据
				memberCards: [], // 用户拥有的会员卡列表
				availableMemberCards: [], // 当前可用的会员卡列表
				selectedMemberCard: null, // 选中的会员卡
				// 标记图标配置
				techMarkerIcon: {
					iconPath: '/static/icons/location.png',
					width: 40,
					height: 40,
					anchor: {
						x: 0.5,
						y: 1
					}
				},
				userMarkerIcon: {
					iconPath: '/static/icons/location.png',
					width: 24,
					height: 24,
					anchor: {
						x: 0.5,
						y: 0.5
					}
				},
				selectedService: null,
				selectedDate: '',
				selectedTime: '',
				availableDates: [],
				availableTimes: [],
				transportOptions: [{
						type: 'taxi',
						name: '出租车',
						price: 100
					},
					{
						type: 'other',
						name: '其他',
						price: 100
					}
				],
				selectedAddress: '',
				showAddressList: false,
				addressList: [],
				totalPrice: 0,
				currentService: null, // 添加当前选择的服务
				remark: '',
				showMiniConfirm: false, // 添加小型确认弹窗的显示状态
				coupons: [], // 用户优惠券列表
				availableCoupons: [], // 可用优惠券列表
				selectedCoupon: null, // 选中的优惠券
				technicianServiceTimes: [], // 技师服务时间数据
				selectedCard: null,
				giftServices: [],
				projectList: [], // 添加项目列表
				isSubmitting: false, // 防止重复提交标记
				polyline: [], // 路线数据
				selectedGiftId: null, // 当前选中的附赠项目ID
				selectedGift: null, // 当前选中的附赠项目
				showUnselectedTips: true, // 添加未选择项提示显示状态
				additionalServiceList: [], // 附加项目列表
				selectedAdditionalServices: [], // 已选择的附加项目ID列表
				additionalServicesMap: {}, // 附加项目映射，用于快速查找价格
				preSelectedServiceId: null, // 保存预选择的服务ID
				preSelectedCategoryId: null, // 保存预选择的分类ID
			}
		},
		watch: {
			// 监听选中的服务和交通方式，计算总价
			selectedService: {
				handler(newVal) {
					this.calculateTotalPrice()
					this.updateAvailableCoupons()
					// 更新可用会员卡
					this.updateAvailableMemberCards()
					this.checkUnselectedTips()
				},
				immediate: true
			},
			selectedDate() {
				this.updateAvailableTimes()
				this.checkUnselectedTips()
			},
			selectedCoupon: {
				handler(newVal) {
					this.calculateTotalPrice()
				},
				immediate: true
			},

			selectedMemberCard: {
				handler(newVal) {
					this.calculateTotalPrice()
				},
				immediate: true
			},
			// 添加对selectedAddress的监听
			selectedAddress: {
				handler(newVal) {
					if (newVal) {
						// 更新地图标记
						this.updateMarkers()
						// 计算距离和时间
						this.calculateDistance()
						// 更新总价
						this.calculateTotalPrice()
					}
				},
				immediate: true
			}
		},
		onLoad(options) {
			if (options.code) {
				this.editUserOpenid(options.code)
			}
			this.checkUserRole()
			// 保存预选择的服务ID
			this.preSelectedServiceId = options.preSelectedServiceId || null
			this.preSelectedCategoryId = options.preSelectedCategoryId || null
			// 处理从home-massage.vue传递的技师信息
			if (options.techName) {
				// 如果传递了完整的技师信息，直接使用
				this.techInfo = {
					id: options.techId,
					name: decodeURIComponent(options.techName || ''),
					title: decodeURIComponent(options.techTitle || ''),
					score: parseFloat(options.techScore || 4.5),
					orders: parseInt(options.techOrders || 0),
					avatar: decodeURIComponent(options.techAvatar || ''),
					latitude: parseFloat(options.techLatitude || 0),
					longitude: parseFloat(options.techLongitude || 0),
					categoryIds: options.categoryIds || ''
				}
				// 如果传递了用户位置信息，直接使用
				if (options.userLatitude && options.userLongitude) {
					this.userLocation = {
						latitude: parseFloat(options.userLatitude),
						longitude: parseFloat(options.userLongitude)
					}
					// 更新地图标记
					this.updateMarkers()
					// 计算与技师的距离
					this.calculateDistance()
				} else {
					// 获取用户当前位置
					this.getCurrentLocation()
				}
				// 直接按技师 ID 加载服务项目，确保与技师后台配置一致
				this.loadServicesByTechnician(this.techInfo.id)
			} else {
				// 如果没有传递完整信息，使用原有的加载方式
				// 获取用户当前位置
				this.getCurrentLocation()
				// 加载技师信息
				if (options.techId) {
					this.loadTechInfo(options.techId)
				}
				// 如果没有技师信息，直接加载所有服务项目
				this.loadAllProjects()
			}
			// 加载其他必要信息
			this.loadAddressList()
			this.initDateTimes()
			// 加载用户优惠券
			this.loadUserCoupons()
			// 加载用户会员卡
			this.loadMemberCards()
			// 只加载附加项目列表，不再全量拉项目，避免覆盖技师专属列表
			this.loadAdditionalServices()
		},
		onShow() {
			this.checkUserRole()
			this.loadAddressList()
		},
		methods: {
			editUserOpenid(code) {
				let userInfo = uni.getStorageSync('userInfo')
				if (!userInfo) {
					uni.reLaunch({
						url: '/pages/login/login'
					})
				}
				uni.request({
					url: `${uni.$config.baseUrl}/wx/wx-service/getOauth2AccessToken`,
					method: 'GET',
					data: {
						code
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data.code === 200) {
							uni.request({
								url: `${uni.$config.baseUrl}/member/member/edit-open-id`,
								method: 'POST',
								data: {
									id: userInfo.memberId,
									openId: res.data.data.openid
								},
								success: (wxRes) => {
									if (wxRes.statusCode === 200 && wxRes.data.code === 200) {
										userInfo.openId = wxRes.data.data.openid
										uni.setStorageSync('userInfo', userInfo)
									}
								}
							})
						}
					}
				})
			},
			editUserOpenid(code) {
				let userInfo = uni.getStorageSync('userInfo')
				if (!userInfo) {
					uni.reLaunch({
						url: '/pages/login/login'
					})
				}
				uni.request({
					url: `${uni.$config.baseUrl}/wx/wx-service/getOauth2AccessToken`,
					method: 'GET',
					data: {
						code
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data.code === 200) {
							uni.request({
								url: `${uni.$config.baseUrl}/member/member/edit-open-id`,
								method: 'POST',
								data: {
									id: userInfo.memberId,
									openId: res.data.data.openid
								},
								success: (wxRes) => {
									if (wxRes.statusCode === 200 && wxRes.data.code === 200) {
										userInfo.openid = wxRes.data.data.openid
										uni.setStorageSync('userInfo', userInfo)
									}
								}
							})
						}
					}
				})
			},
			checkUserRole() {
				const userInfoStr = uni.getStorageSync('userInfo')
				let userInfo = null
				if (userInfoStr) {
					try {
						if (typeof userInfoStr === 'string') {
							const parsed = JSON.parse(userInfoStr)
							if (parsed.code === 200 && parsed.data) {
								userInfo = parsed.data
							} else {
								userInfo = parsed
							}
						} else {
							userInfo = userInfoStr
						}
						if (userInfo && userInfo.role === 'technician') {
							this.isTechnician = true
							uni.showModal({
								title: '提示',
								content: '您当前登录的账号为技师账号，不可预约',
								showCancel: false,
								confirmText: '知道了'
							})
						}
					} catch (e) {}
				}
			},
			loadAddressList() {
				const userInfoStr = uni.getStorageSync('userInfo')
				let userInfo = null
				if (userInfoStr) {
					try {
						// 如果是字符串，尝试解析
						if (typeof userInfoStr === 'string') {
							const parsed = JSON.parse(userInfoStr)
							// 检查是否是登录响应格式
							if (parsed.code === 200 && parsed.data) {
								userInfo = parsed.data
							} else {
								userInfo = parsed
							}
						} else {
							// 如果不是字符串，直接使用
							userInfo = userInfoStr
						}
					} catch (e) {
						console.error('解析用户信息失败', e)
						// 解析失败时，尝试直接使用
						userInfo = userInfoStr
					}
				}
				const memberId = userInfo.memberId
				uni.request({
					url: `${uni.$config.baseUrl}/address/address/listAll`,
					method: 'GET',
					data: {
						id: memberId
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data && res.data.code === 200) {
							this.addressList = res.data.rows || []
							// 如果地址列表为空，提示用户并跳转到地址管理页面
							if (res.data.rows.length === 0) {
								uni.showModal({
									title: '提示',
									content: '您还没有添加服务地址，是否前往添加？',
									confirmText: '去添加',
									cancelText: '取消',
									success: (res) => {
										if (res.confirm) {
											uni.navigateTo({
												url: '/pages/address/address'
											})
										}
									}
								})
								return
							}
							// 自动选择默认地址
							if (this.addressList.length > 0) {
								// 查找默认地址
								const defaultAddress = this.addressList.find(addr => addr.isDefault === 1)
								// 如果有默认地址则选择默认地址，否则选择第一个地址
								this.selectedAddress = defaultAddress || this.addressList[0]
							}
						} else {
							uni.showToast({
								title: res.data.msg || '获取地址列表失败',
								icon: 'none'
							})
						}
					},
					fail: (err) => {
						uni.showToast({
							title: '网络请求失败',
							icon: 'none'
						})
					}
				})
			},
			// 获取当前位置
			getCurrentLocation() {
				uni.showLoading({
					title: '定位中...'
				})
				// 调用后端IP定位接口
				uni.request({
					url: `${uni.$config.baseUrl}/map/location/v1/ip`,
					method: 'GET',
					data: {
						key: 'GJZBZ-5ZV6G-ID2QK-Q6ODP-WNIPQ-HZFB4'
					},
					success: (res) => {
						if (res.data.code === 200) {
							const location = res.data.data.location
							if (location) {
								this.userLocation = {
									latitude: location.lat,
									longitude: location.lng
								}
								// 更新地图标记
								this.updateMarkers()
								// 计算与技师的距离
								this.calculateDistance()
							} else {
								uni.showToast({
									title: '无法获取位置信息',
									icon: 'none'
								})
							}
						} else {
							uni.showToast({
								title: res.data.msg || '获取位置失败',
								icon: 'none'
							})
						}
					},
					fail: (err) => {
						uni.showToast({
							title: '获取位置失败',
							icon: 'none'
						})
					},
					complete: () => {
						uni.hideLoading()
					}
				})
			},
			// 计算与技师的距离
			calculateDistance() {
				// 使用选中地址的经纬度作为起点
				const from = `${this.selectedAddress.latitude},${this.selectedAddress.longitude}`;
				const to = `${this.techInfo.latitude},${this.techInfo.longitude}`;
				// 调用后端接口获取路线规划信息
				uni.request({
					url: `${uni.$config.baseUrl}/map/direction/v1/driving`,
					method: 'GET',
					data: {
						from: from,
						to: to,
						key: 'GJZBZ-5ZV6G-ID2QK-Q6ODP-WNIPQ-HZFB4'
					},
					success: (res) => {
						if (res.data.code === 200) {
							const result = res.data.data;
							if (result && result.routes && result.routes.length > 0) {
								const route = result.routes[0];
								// 距离单位为米，转换为千米
								this.distance = (route.distance / 1000).toFixed(1);
								// 时间单位为秒，转换为分钟
								this.arrivalTime = route.duration;
								// 计算交通费用
								if (route.taxi_fare && route.taxi_fare.fare > 0) {
									// 使用API返回的出租车费用
									this.transportFee = route.taxi_fare.fare;
								} else {
									// 根据距离计算交通费用
									const baseFee = 13; // 基础费用10元
									const perKmFee = 3; // 每公里2元
									const distanceKm = parseFloat(this.distance);
									this.transportFee = Math.round(baseFee + (distanceKm * perKmFee));
								}
								// 更新地图路线
								if (route.polyline) {
									const points = this.decodePolyline(route.polyline);
									this.updateMapRoute(points);
								}
								// 更新总价
								this.calculateTotalPrice();
							} else {
								// 使用默认值
								this.distance = 3.0;
								this.arrivalTime = 12;
								this.transportFee = 0;
								this.calculateTotalPrice();
							}
						} else {
							// 使用默认值
							this.distance = 3.0;
							this.arrivalTime = 12;
							this.transportFee = 0;
							this.calculateTotalPrice();
						}
					},
					fail: (err) => {
						// 使用默认值
						this.distance = 3.0;
						this.arrivalTime = 12;
						this.transportFee = 0;
						this.calculateTotalPrice();
					}
				});
			},
			// 更新地图标记
			updateMarkers() {
				// 使用选中地址的经纬度作为目标位置
				const targetLocation = this.selectedAddress ? {
					latitude: this.selectedAddress.latitude,
					longitude: this.selectedAddress.longitude
				} : this.userLocation

				this.markers = [{
						id: 1,
						latitude: targetLocation.latitude,
						longitude: targetLocation.longitude,
						...this.userMarkerIcon,
						callout: {
							content: '服务地址',
							color: '#333333',
							fontSize: 12,
							borderRadius: 4,
							padding: 6,
							display: 'ALWAYS',
							bgColor: '#FFFFFF',
							borderWidth: 1,
							borderColor: '#007AFF'
						}
					},
					{
						id: 2,
						latitude: this.techInfo.latitude,
						longitude: this.techInfo.longitude,
						...this.techMarkerIcon,
						callout: {
							content: this.techInfo.name,
							color: '#333333',
							fontSize: 14,
							borderRadius: 4,
							padding: 8,
							display: 'ALWAYS',
							bgColor: '#FFFFFF',
							borderWidth: 1,
							borderColor: '#00B26A'
						}
					}
				]
				// 更新地图视野以包含所有标记点
				this.$nextTick(() => {
					const mapContext = uni.createMapContext('map', this)
					if (mapContext) {
						mapContext.includePoints({
							points: [{
									latitude: targetLocation.latitude,
									longitude: targetLocation.longitude
								},
								{
									latitude: this.techInfo.latitude,
									longitude: this.techInfo.longitude
								}
							],
							padding: [80, 80, 80, 80]
						})
					}
				})
			},
			// 加载技师信息
			loadTechInfo(techId) {
				uni.showLoading({
					title: '加载中...'
				})
				uni.request({
					url: `${uni.$config.baseUrl}/technician/technician/detail`,
					method: 'GET',
					data: {
						id: techId
					},
					header: {
						'content-type': 'application/json'
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data && res.data.code === 200) {
							// 处理技师详情数据
							const tech = res.data.data // 直接获取data中的技师数据
							if (tech) {
								this.techInfo = {
									id: tech.id,
									name: tech.name || '未知技师',
									avatar: tech.avatar || 'https://img.yzcdn.cn/vant/cat.jpeg',
									title: tech.technicianType || '高级按摩师',
									score: tech.score || 4.9,
									orders: tech.appointmentCount || 0,
									tags: tech.tags ? tech.tags.split(',') : ['专业', '耐心', '守时'],
									latitude: tech.latitude || 39.908892,
									longitude: tech.longitude || 116.397877,
									introduction: tech.introduction || '暂无简介'
								}

								// 获取技师关联的项目列表
								this.loadTechnicianProjects(tech.id)

								// 更新标记和距离
								this.updateMarkers()

								// 调整地图视野以显示当前位置和技师位置
								this.$nextTick(() => {
									this.adjustMapView()
								})
							} else {
								uni.showToast({
									title: '未找到技师信息',
									icon: 'none'
								})
							}
						} else {
							uni.showToast({
								title: res.data.msg || '获取技师信息失败',
								icon: 'none'
							})
						}
					},
					fail: (err) => {
						uni.showToast({
							title: '网络请求失败，请检查网络',
							icon: 'none'
						})
					},
					complete: () => {
						uni.hideLoading()
					}
				})
			},
			// 添加新方法：调整地图视野以显示当前位置和技师位置
			adjustMapView() {
				if (!this.techInfo || !this.techInfo.latitude || !this.techInfo.longitude) {
					return
				}
				const mapContext = uni.createMapContext('map', this)
				if (mapContext) {
					// 计算中心点
					const centerLat = (this.userLocation.latitude + this.techInfo.latitude) / 2
					const centerLng = (this.userLocation.longitude + this.techInfo.longitude) / 2
					// 计算合适的缩放级别
					const latDiff = Math.abs(this.userLocation.latitude - this.techInfo.latitude)
					const lngDiff = Math.abs(this.userLocation.longitude - this.techInfo.longitude)
					const maxDiff = Math.max(latDiff, lngDiff)
					// 根据距离差异设置缩放级别
					let scale = 14
					if (maxDiff > 0.1) scale = 12
					if (maxDiff > 0.2) scale = 11
					if (maxDiff > 0.3) scale = 10
					if (maxDiff < 0.01) scale = 15
					// 更新地图视野
					mapContext.includePoints({
						points: [{
								latitude: this.userLocation.latitude,
								longitude: this.userLocation.longitude
							},
							{
								latitude: this.techInfo.latitude,
								longitude: this.techInfo.longitude
							}
						],
						padding: [80, 80, 80, 80]
					})
				}
			},
			// 获取技师关联的项目列表
			loadTechnicianProjects(technicianId) {
				uni.request({
					url: `${uni.$config.baseUrl}/project/project/technician/${technicianId}`,
					method: 'GET',
					success: (res) => {
						if (res.statusCode === 200 && res.data && res.data.code === 200) {
							const projectList = res.data.rows || []
							// 处理项目数据
							this.services = projectList.map(project => ({
								id: project.id,
								name: project.projectName || '',
								duration: project.duration || 60,
								price: project.price || 0,
								img: project.imgUrls.split(',')[0],
								categoryIds: project.categoryIds || project.categoryId || '',
								originalPrice: project.originalPrice || 0
							}))
							// 如果有预选择的服务ID，自动选中该服务
							if (this.preSelectedServiceId) {
								const preSelectedService = this.services.find(service =>
									service.id.toString() === this.preSelectedServiceId.toString()
								)
								if (preSelectedService) {
									this.selectService(preSelectedService)
								}
							}
							// 如果只传了分类id，尝试根据分类匹配第一个项目
							if (!this.selectedService && this.preSelectedCategoryId) {
								const matchSvc = this.services.find(svc => {
									if (!svc.categoryIds) return false;
									return svc.categoryIds.split(',').includes(this
										.preSelectedCategoryId.toString());
								});
								if (matchSvc) {
									this.selectService(matchSvc);
								}
							}
						} else {
							// 设置默认项目列表
							this.services = []
						}
					},
					fail: (err) => {
						this.services = []
					}
				})
			},
			// 选择服务
			selectService(service) {
				// 更新当前服务，但不主动加载时间
				this.selectedService = service.id
				this.currentService = service
				// 清空已选时间与时段列表，等待用户重新点击日期再拉接口
				this.selectedTime = ''
				this.availableTimes = []
			},
			// 选择日期
			selectDate(date) {
				// 兼容旧入口
				this.fetchAvailableTimes(date)
			},
			// 选择时间
			selectTime(time) {
				if (!time.disabled) {
					this.selectedTime = time.value
				}
			},
			// 初始化日期和时间
			initDateTimes() {
				const now = new Date()
				const dates = []
				// 生成三天的日期选项
				for (let i = 0; i < 3; i++) {
					const date = new Date(now)
					date.setDate(now.getDate() + i)
					dates.push({
						value: date.toISOString().split('T')[0],
						day: ['今天', '明天', '后天'][i],
						date: `${date.getMonth() + 1}月${date.getDate()}日`
					})
				}
				this.availableDates = dates
				this.selectedDate = '' // 等用户点击日期后再加载时间
				this.availableTimes = []
				this.getTechnicianServiceTimes(this.techInfo.id, this.selectedDate)
			},
			// 获取技师服务时间
			async getTechnicianServiceTimes(technicianId, appointmentDate) {
				try {
					// 首先尝试获取技师服务时间
					const res = await uni.request({
						url: `${uni.$config.baseUrl}/servicetime/servicetime/listAll`,
						method: 'GET',
						data: {
							techId: technicianId,
							serviceDate: appointmentDate // 格式为yyyy-MM-dd
						}
					})
					// 检查主接口返回结果
					if (res.statusCode === 200 && res.data.code === 200) {
						if (res.data.rows && res.data.rows.length > 0) {
							// 如果服务时间数据不为空，直接使用
							this.technicianServiceTimes = res.data.rows
							return this.technicianServiceTimes
						} else {
							// 如果服务时间数据为空，尝试获取技师工作时间
							return await this.getTechnicianWorkSchedule(technicianId, appointmentDate)
						}
					} else {
						// 尝试获取技师工作时间作为备选
						return await this.getTechnicianWorkSchedule(technicianId, appointmentDate)
					}
				} catch (error) {
					// 发生异常时，尝试获取技师工作时间作为备选
					return await this.getTechnicianWorkSchedule(technicianId, appointmentDate)
				}
			},
			// 获取技师工作时间
			async getTechnicianWorkSchedule(technicianId, appointmentDate) {
				try {
					const res = await uni.request({
						url: `${uni.$config.baseUrl}/schedule/schedule/listAll`,
						method: 'GET',
						data: {
							technicianId: technicianId,
							serviceDate: appointmentDate // 格式为yyyy-MM-dd
						}
					})
					if (res.statusCode === 200 && res.data.code === 200 && res.data.rows && res.data.rows.length > 0) {
						// 将工作时间数据转换为服务时间格式
						const scheduleData = res.data.rows.map(item => ({
							startTime: item.startTime,
							endTime: item.endTime,
							workDays: item.workDays,
							serviceDuration: '', // 空字符串表示无预约
							servicedDuration: '' // 空字符串表示无不可服务时间
						}))
						this.technicianServiceTimes = scheduleData
						return scheduleData
					} else {
						this.technicianServiceTimes = []
						return []
					}
				} catch (error) {
					this.technicianServiceTimes = []
					return []
				}
			},
			// 更新可用时间列表
			async updateAvailableTimes() {
				const today = new Date().toISOString().split('T')[0]
				const isToday = this.selectedDate === today
				const currentHour = new Date().getHours()
				const currentMinutes = new Date().getMinutes()

				// 优先走后端统一接口
				if (this.techInfo.id && this.currentService && this.currentService.duration && this.selectedDate) {
					try {
						const resp = await uni.request({
							url: `${uni.$config.baseUrl}/servicetime/servicetime/get-server-time-list`,
							method: 'POST',
							header: {
								'content-type': 'application/json'
							},
							data: {
								date: this.selectedDate,
								techId: this.techInfo.id,
								duration: this.currentService.duration
							}
						})
						if (resp.statusCode === 200 && resp.data.code === 200) {
							const list = (resp?.data?.data || res.data.data || []).map(it => ({
								label: it.timePoint,
								value: it.timePoint,
								key: `${this.selectedDate}_${it.timePoint}`,
								disabled: !!it.disabled
							}))
							this.availableTimes = list
							return
						}
					} catch (e) {
						// ignore and fallback
					}
				}

				// ------- 旧逻辑回退 -------
				if (this.techInfo.id && this.selectedDate) {
					const serviceTimes = await this.getTechnicianServiceTimes(this.techInfo.id, this.selectedDate)
					if (serviceTimes && serviceTimes.length > 0) {
						this.generateTimeSlotsFromServiceTimes(serviceTimes, isToday, currentHour, currentMinutes)
						return
					}
				}
				this.generateDefaultTimeSlots(isToday, currentHour, currentMinutes)
			},
			// 从技师服务时间生成可选时间段
			generateTimeSlotsFromServiceTimes(serviceTimes, isToday, currentHour, currentMinutes) {
				const times = []
				const today = new Date().toISOString().split('T')[0]
				const isCurrentDay = this.selectedDate === today
				const usedTimes = new Set() // 用于跟踪已使用的时间
				// 确保serviceTimes是数组且不为空
				if (!Array.isArray(serviceTimes) || serviceTimes.length === 0) {
					this.generateDefaultTimeSlots(isToday, currentHour, currentMinutes)
					return
				}
				// 处理每个服务时间段
				for (const serviceTime of serviceTimes) {
					// 添加空值检查
					if (!serviceTime || typeof serviceTime !== 'object') continue
					// 确保startTime和endTime存在且格式正确
					if (!serviceTime.startTime || !serviceTime.endTime) continue
					// 解析开始和结束时间
					const startTimeParts = serviceTime.startTime.split(':')
					const endTimeParts = serviceTime.endTime.split(':')
					// 确保时间格式正确
					if (startTimeParts.length < 2 || endTimeParts.length < 2) continue
					const startHour = parseInt(startTimeParts[0])
					const startMinute = parseInt(startTimeParts[1])
					const endHour = parseInt(endTimeParts[0])
					const endMinute = parseInt(endTimeParts[1])
					// 验证时间值的有效性
					if (isNaN(startHour) || isNaN(startMinute) || isNaN(endHour) || isNaN(endMinute)) continue
					// 计算总分钟数
					const startTotalMinutes = startHour * 60 + startMinute
					const endTotalMinutes = endHour * 60 + endMinute
					// 确保结束时间大于开始时间
					if (endTotalMinutes <= startTotalMinutes) continue
					// 生成该时间段内的时间选项（每30分钟一个选项）
					for (let totalMinutes = startTotalMinutes; totalMinutes <= endTotalMinutes; totalMinutes += 30) {
						const hour = Math.floor(totalMinutes / 60)
						const minute = totalMinutes % 60
						const timeValue = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
						// 如果这个时间已经被使用，跳过
						if (usedTimes.has(timeValue)) continue
						usedTimes.add(timeValue)
						// 判断时间是否可用
						let disabled = false
						// 如果是当天，检查是否已过时间
						if (isCurrentDay && (hour < currentHour || (hour === currentHour && minute <= currentMinutes))) {
							disabled = true
						}
						// 检查是否与已预约时间冲突
						if (this.isTimeSlotConflict(timeValue, serviceTime.serviceDuration, serviceTime
								.servicedDuration)) {
							disabled = true
						}
						times.push({
							label: timeValue,
							value: timeValue,
							key: `${this.selectedDate}_${timeValue}`, // 添加唯一的key
							disabled: disabled
						})
					}
				}
				// 如果没有生成任何时间选项，使用默认时间段
				if (times.length === 0) {
					this.generateDefaultTimeSlots(isToday, currentHour, currentMinutes)
					return
				}
				// 排序时间选项
				times.sort((a, b) => {
					const [aHour, aMinute] = a.value.split(':').map(Number)
					const [bHour, bMinute] = b.value.split(':').map(Number)
					return aHour * 60 + aMinute - (bHour * 60 + bMinute)
				})
				this.availableTimes = times
				// 如果当前选择的时间变为不可用，清除选择
				if (this.selectedTime) {
					const selectedTimeItem = times.find(t => t.value === this.selectedTime)
					if (!selectedTimeItem || selectedTimeItem.disabled) {
						this.selectedTime = ''
					}
				}
			},
			// 判断时间段是否与已预约时间冲突
			isTimeSlotConflict(startTime, serviceDuration, servicedDuration) {
				if (!serviceDuration && !servicedDuration) return false
				// 检查时间是否在列表中
				if (serviceDuration && serviceDuration.split(',').includes(startTime)) {
					return true
				}
				if (servicedDuration && servicedDuration.split(',').includes(startTime)) {
					return true
				}
				return false
			},
			// 生成默认时间段
			generateDefaultTimeSlots(isToday, currentHour, currentMinute) {
				const times = []
				// 生成10:00-22:00的时间选项，每半小时一个时间段
				for (let hour = 8; hour < 24; hour++) {
					for (let minute = 0; minute < 60; minute += 30) {
						const timeValue = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
						const disabled = isToday && (hour < currentHour || (hour === currentHour && minute <=
							currentMinute))
						times.push({
							value: timeValue,
							text: timeValue,
							disabled
						})
					}
				}
				this.availableTimes = times
			},
			// 获取服务结束时间信息
			getEndTimeInfo(startTime) {
				if (!startTime || !this.currentService?.duration) return ''
				const [hour, minute] = startTime.split(':').map(Number)
				const endTime = new Date()
				endTime.setHours(hour)
				endTime.setMinutes(minute + this.currentService.duration)
				return `至 ${endTime.getHours().toString().padStart(2, '0')}:${endTime.getMinutes().toString().padStart(2, '0')}`
			},
			// 切换地址列表显示状态
			toggleAddressList() {
				this.showAddressList = !this.showAddressList
			},
			// 选择地址
			selectAddress(address) {
				this.selectedAddress = address
				this.showAddressList = false
				// 计算与技师的直线距离（单位：千米）
				const latDiff = Math.abs(address.latitude - this.techInfo.latitude)
				const lngDiff = Math.abs(address.longitude - this.techInfo.longitude)
				const distance = Math.sqrt(latDiff * latDiff + lngDiff * lngDiff) * 111 // 转换为大约的千米距离
				// 根据实际距离动态设置缩放级别
				if (distance > 100) this.mapScale = 6 // 超过20公里
				else if (distance > 50) this.mapScale = 7 // 超过20公里
				else if (distance > 20) this.mapScale = 9 // 超过20公里
				else if (distance > 10) this.mapScale = 10 // 10-20公里
				else if (distance > 5) this.mapScale = 11 // 5-10公里
				else if (distance > 3) this.mapScale = 12 // 3-5公里
				else if (distance > 1) this.mapScale = 13 // 1-3公里
				else if (distance > 0.5) this.mapScale = 14 // 500米-1公里
				else if (distance > 0.2) this.mapScale = 15 // 200-500米
				else this.mapScale = 16 // 200米以内
				// 更新地图标记
				this.markers = [{
						id: 1,
						latitude: address.latitude,
						longitude: address.longitude,
						...this.userMarkerIcon,
						callout: {
							content: '服务地址',
							color: '#333333',
							fontSize: 12,
							borderRadius: 4,
							padding: 6,
							display: 'ALWAYS',
							bgColor: '#FFFFFF',
							borderWidth: 1,
							borderColor: '#007AFF'
						}
					},
					{
						id: 2,
						latitude: this.techInfo.latitude,
						longitude: this.techInfo.longitude,
						...this.techMarkerIcon,
						callout: {
							content: this.techInfo.name,
							color: '#333333',
							fontSize: 14,
							borderRadius: 4,
							padding: 8,
							display: 'ALWAYS',
							bgColor: '#FFFFFF',
							borderWidth: 1,
							borderColor: '#00B26A'
						}
					}
				]
				// 更新地图视野
				this.$nextTick(() => {
					const mapContext = uni.createMapContext('map', this)
					if (mapContext) {
						mapContext.includePoints({
							points: [{
									latitude: address.latitude,
									longitude: address.longitude
								},
								{
									latitude: this.techInfo.latitude,
									longitude: this.techInfo.longitude
								}
							],
							padding: [80, 80, 80, 80]
						})
					}
				})
				// 重新计算距离和时间
				this.calculateDistance()
				// 更新总价
				this.calculateTotalPrice()
			},
			// 跳转到地址管理页面
			goToAddressManage() {
				uni.navigateTo({
					url: '/pages/address/address'
				})
			},
			// 加载用户优惠券
			loadUserCoupons() {
				const userInfoStr = uni.getStorageSync('userInfo')
				let userInfo = null

				if (userInfoStr) {
					try {
						if (typeof userInfoStr === 'string') {
							const parsed = JSON.parse(userInfoStr)
							if (parsed.code === 200 && parsed.data) {
								userInfo = parsed.data
							} else {
								userInfo = parsed
							}
						} else {
							userInfo = userInfoStr
						}
					} catch (e) {
						userInfo = userInfoStr
					}
				}
				if (!userInfo || !userInfo.memberId) {
					return
				}
				uni.request({
					url: `${uni.$config.baseUrl}/usercoupons/usercoupons/listAllByUserId/${userInfo.memberId}`,
					method: 'GET',
					success: (res) => {
						if (res.statusCode === 200 && res.data && res.data.code === 200) {
							this.coupons = res.data.rows || []
							this.updateAvailableCoupons()
						}
					}
				})
			},
			// 更新可用优惠券列表
			updateAvailableCoupons() {
				if (!this.selectedService) {
					this.availableCoupons = []
					this.selectedCoupon = null
					return
				}
				const selectedServiceInfo = this.services.find(s => s.id === this.selectedService)
				if (!selectedServiceInfo) {
					this.availableCoupons = []
					this.selectedCoupon = null
					return
				}
				// 筛选可用优惠券
				this.availableCoupons = this.coupons.filter(coupon => {
					// 检查优惠券是否过期
					const now = new Date()
					// 将 "2025-03-21 12:00:00" 格式的字符串转换为 Date 对象
					const dateString = coupon.coupons.validityEnd;
					// 拆分日期和时间部分
					const [datePart, timePart] = dateString.split(' ');
					const [year, month, day] = datePart.split('-').map(Number);
					const [hours, minutes, seconds] = timePart.split(':').map(Number);
					// 构造 Date 对象（注意：月份从 0 开始，需减 1）
					const expireDate = new Date(year, month - 1, day, hours, minutes, seconds);
					if (now > expireDate) return false
					// 检查优惠券是否已使用
					if (coupon.coupons.status !== 1) return false
					// 检查优惠券是否适用于当前服务
					if (coupon.coupons && coupon.coupons.projectIds) {
						const projectIds = coupon.coupons.projectIds.split(',')
						if (!projectIds.includes(this.selectedService.toString())) return false
					}
					// 检查订单金额是否满足优惠券使用条件
					if (coupon.coupons && coupon.coupons.minAmount && selectedServiceInfo.price < coupon.coupons
						.minAmount) return false
					return true
				})
				// 如果当前选中的优惠券不可用，清除选择
				if (this.selectedCoupon && !this.availableCoupons.find(c => c.id === this.selectedCoupon.id)) {
					this.selectedCoupon = null
				}
			},
			// 选择优惠券
			selectCoupon(coupon) {
				if (this.selectedCoupon && this.selectedCoupon.id === coupon.id) {
					this.selectedCoupon = null
				} else {
					this.selectedCoupon = coupon
				}
			},
			// 加载用户会员卡
			loadMemberCards() {
				const userInfoStr = uni.getStorageSync('userInfo')
				let userInfo = null
				if (userInfoStr) {
					try {
						if (typeof userInfoStr === 'string') {
							const parsed = JSON.parse(userInfoStr)
							if (parsed.code === 200 && parsed.data) {
								userInfo = parsed.data
							} else {
								userInfo = parsed
							}
						} else {
							userInfo = userInfoStr
						}
					} catch (e) {
						userInfo = userInfoStr
					}
				}
				if (!userInfo || !userInfo.memberId) {
					return
				}
				uni.request({
					url: `${uni.$config.baseUrl}/usercard/usercard/listByUid`,
					method: 'GET',
					data: {
						memberId: userInfo.memberId
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data && res.data.code === 200) {
							this.memberCards = res.data.rows || []
							this.updateAvailableMemberCards()
						}
					}
				})
			},
			// 更新可用会员卡列表
			updateAvailableMemberCards() {
				if (!this.selectedService) {
					this.availableMemberCards = []
					this.selectedMemberCard = null
					return
				}
				// 筛选可用会员卡
				this.availableMemberCards = this.memberCards.filter(card => {
					// 检查会员卡是否有效
					if (card.status !== 1 || card.isDeleted === 1) return false
					if (!card.memberCard) return false
					else {
						if (card.memberCard.cardType === 1 && card.balance <= 0) return false
						else if (card.memberCard.cardType === 2 && card.remainingTimes <= 0) return false
					}
					// 检查项目是否可用
					if (card.memberCard.projectIds)
						return card.memberCard.projectIds.split(',').includes(this.selectedService.toString())
					return false
				})
				// 如果当前选中的会员卡不可用，清除选择
				if (this.selectedMemberCard && !this.availableMemberCards.find(c => c.id === this.selectedMemberCard.id)) {
					this.selectedMemberCard = null
				}
			},
			// 选择会员卡
			selectMemberCard(card) {
				if (this.selectedMemberCard && this.selectedMemberCard.id === card.id) {
					this.selectedMemberCard = null;
					this.selectedCard = null;
					this.giftServices = [];
				} else {
					this.selectedMemberCard = card;
					this.selectedCard = card;
					if (card && card.cardId) {
						// 查询赠送项目列表
						request({
							url: `${uni.$config.baseUrl}/project/project/get-list-by-card-id`,
							method: 'GET',
							data: {
								cardId: card.cardId
							}
						}).then(res => {
							this.giftProject = {
								type: card.memberCard.cardType,
								balance: card.balance,
								status: card.giftProjectStatus,
								num: card.numberGiftItems,
								cardId: card.id,
								expireTime: card.memberCard.expireTime,
								list: res.data
							}
						})
					}
				}
				this.calculateTotalPrice();
			},
			// 修改计算总价方法
			calculateTotalPrice() {
				let total = 0
				// 添加服务费用
				if (this.selectedService) {
					const service = this.services.find(s => s.id === this.selectedService)
					if (service) {
						total += service.price
					}
				}
				// 添加附加项目费用
				this.selectedAdditionalServices.forEach(serviceId => {
					const service = this.additionalServicesMap[serviceId]
					if (service) {
						total += service.price
					}
				})
				// 添加交通费用
				total += this.transportFee
				// 应用优惠券
				if (this.selectedCoupon && this.selectedCoupon.coupons) {
					total = Math.max(0, total - this.selectedCoupon.coupons.amount)
				}
				// 如果选择了可用会员卡，实付金额为0
				if (this.selectedMemberCard) {
					total = this.transportFee
				}
				this.totalPrice = total
			},
			// 显示确认对话框
			showConfirmDialog() {
				// 检查是否是技师账号
				if (this.isTechnician) {
					uni.showModal({
						title: '提示',
						content: '您当前登录的账号为技师账号，不可预约',
						showCancel: false,
						confirmText: '知道了'
					})
					return
				}
				// 检查必要信息是否已选择
				if (!this.selectedService) {
					uni.showToast({
						title: '请选择服务项目',
						icon: 'none'
					})
					return
				}
				if (!this.selectedDate || !this.selectedTime) {
					uni.showToast({
						title: '请选择服务时间',
						icon: 'none'
					})
					return
				}
				if (!this.selectedAddress) {
					uni.showToast({
						title: '请选择服务地址',
						icon: 'none'
					})
					return
				}
				this.showMiniConfirm = true
			},
			// 取消确认
			cancelConfirm() {
				this.showMiniConfirm = false
			},
			submitOrder() {
				if (this.isSubmitting) {
					uni.showToast({
						title: '请勿重复提交',
						icon: 'none'
					})
					return
				}
				if (this.isTechnician) {
					uni.showModal({
						title: '提示',
						content: '您当前登录的账号为技师账号，不可预约',
						showCancel: false,
						confirmText: '知道了'
					})
					return
				}
				if (!this.selectedAddress) {
					uni.showToast({
						title: '请选择服务地址',
						icon: 'none'
					})
					return
				}
				this.showMiniConfirm = false // 关闭确认弹窗
				this.isSubmitting = true
				const userInfo = uni.getStorageSync('userInfo')
				if (!userInfo.openId) {
					uni.showModal({
						title: '微信授权提示',
						content: '首次支付需要绑定微信账号，是否立即前往授权？',
						confirmText: '去授权',
						cancelText: '取消',
						success: res => {
							if (res.confirm) {
								const currentUrl = encodeURIComponent(window.location.href);
								const appId = uni.$config.wxAppId;
								const redirectUrl =
									`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${currentUrl}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`;
								window.location.href = redirectUrl;
							}
						},
						fail: (err) => {
							uni.showToast({
								title: JSON.stringify(err),
								icon: 'none',
								duration: 2000
							});
						},
					});
					return
				}
				const selectedServiceInfo = this.services.find(s => s.id === this.selectedService)
				// 构建预约订单数据
				const appointmentOrders = {
					userId: this.getCurrentMemberId(), // 使用统一方法获取memberId
					orderType: 2, // 2-上门服务
					img: selectedServiceInfo.img,
					serviceId: selectedServiceInfo.id,
					serviceName: selectedServiceInfo.name,
					servicePrice: selectedServiceInfo.price,
					serviceDuration: selectedServiceInfo.duration,
					// 技师信息
					technicianId: this.techInfo.id,
					technicianName: this.techInfo.name,
					// 预约时间信息
					appointmentDate: this.selectedDate,
					appointmentTime: this.selectedTime + ":00",
					// 地址信息
					addressId: this.selectedAddress.id,
					receiverName: this.selectedAddress.recipientName,
					receiverPhone: this.selectedAddress.recipientPhone,
					province: this.selectedAddress.province,
					city: this.selectedAddress.city,
					district: this.selectedAddress.district,
					addressDetail: this.selectedAddress.detailAddress,
					latitude: this.selectedAddress.latitude,
					longitude: this.selectedAddress.longitude,
					// 交通方式
					transportType: 'driving',
					transportPrice: this.transportFee,
					// 订单状态
					orderStatus: this.selectedMemberCard ? 1 : 0,
					paymentStatus: this.selectedMemberCard ? 1 : 0, // 会员卡支付时为1（已支付），否则为0（未支付）
					paymentAmount: this.totalPrice,
					// 备注信息
					remark: this.remark,
					// 优惠券和会员卡ID
					couponId: this.selectedCoupon ? this.selectedCoupon.id : null,
					cardId: this.selectedMemberCard ? this.selectedMemberCard.id : null,
					// 附赠项目ID
					giftServiceId: this.selectedGift && this.selectedGift.id ? this.selectedGift.id : null,
					// 添加附加服务信息
					additionalService: this.selectedAdditionalServices.map(id => {
						const service = this.additionalServicesMap[id]
						return service.projectName
					}).join(','),
				}
				// 显示加载中
				uni.showLoading({
					title: '提交中...'
				})
				if (appointmentOrders.couponId) {
					if (!this.selectedCoupon.coupons.amount) {
						uni.showToast({
							title: '会员卡暂无金额',
							icon: 'error',
							duration: 2000
						})
						return
					}
					const amount = appointmentOrders.paymentAmount - this.selectedCoupon.coupons.amount
					appointmentOrders.paymentAmount = amount < 0 ? 0 : amount
					appointmentOrders.orderStatus = 1
					appointmentOrders.paymentStatus = 1
				}
				// 调用后端接口
				uni.request({
					url: `${uni.$config.baseUrl}/orders/orders`,
					method: 'POST',
					data: appointmentOrders,
					success: (res) => {
						if (res.statusCode === 200 && res.data.code === 200) {
							let orderid = res.data.data
							// 如果使用了优惠券，更新优惠券状态
							if (this.selectedCoupon) {
								if (appointmentOrders.paymentAmount <= 0) {
									setTimeout(() => {
										uni.navigateTo({
											url: '/pages/my-orders/my-orders'
										})
									}, 2000)
								}
								return
							}
							// 如果使用会员卡支付，直接完成订单
							if (this.selectedMemberCard) {
								uni.showToast({
									title: '预约成功',
									icon: 'success',
									duration: 2000,
									success: () => {
										setTimeout(() => {
											uni.navigateTo({
												url: '/pages/my-orders/my-orders'
											})
										}, 2000)
									}
								})
								// 会员卡支付情况下重置提交状态
								this.isSubmitting = false
								return
							}
							// 走与"到店预约"相同的统一支付页面逻辑
							const paymentData = {
								payAmount: this.totalPrice,
								orderType: 3, // 预约订单
								orderDesc: selectedServiceInfo.name,
								callbackUrl: '/pages/my-orders/my-orders',
								paymentParams: {
									orderId: orderid
								}
							}
							uni.setStorageSync('paymentData', paymentData)
							uni.redirectTo({
								url: '/pages/pay-public/pay-public?login=false'
							})
							// 页面已跳转，后续逻辑不再执行
							return
						} else {
							uni.showToast({
								title: res.data.msg || '预约失败',
								icon: 'none'
							})
							// 订单创建失败，重置提交状态
							this.isSubmitting = false
						}
					},
					fail: (err) => {
						console.error('预约失败:', err)
						uni.showToast({
							title: '网络请求失败',
							icon: 'none'
						})
						// 网络请求失败，重置提交状态
						this.isSubmitting = false
					},
					complete: () => {
						uni.hideLoading()
						// 如果是会员卡支付，在complete中确保重置状态
						if (this.selectedMemberCard) {
							this.isSubmitting = false
						}
					}
				})
			},
			// 更新优惠券状态
			updateCouponStatus(coupon) {
				try {
					const updateData = {
						id: coupon.id,
						status: 2, // 2-已使用
						useTime: new Date().toISOString()
					}

					const res = uni.request({
						url: `${uni.$config.baseUrl}/usercoupons/usercoupons/update`,
						method: 'POST',
						data: updateData
					})

					if (res.statusCode === 200 && res.data.code === 200) {
						console.log('优惠券状态更新成功')
						// 更新本地优惠券数据
						this.loadUserCoupons()
					} else {
						console.error('优惠券状态更新失败:', res.data.msg)
					}
				} catch (error) {
					console.error('更新优惠券状态异常:', error)
				}
			},
			// 加载所有项目列表
			loadAllProjects() {
				uni.request({
					url: `${uni.$config.baseUrl}/project/project/listAll`,
					method: 'GET',
					data: {
						status: 1
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data && res.data.code === 200) {
							const projectList = res.data.rows || []
							// 处理项目数据格式，确保与页面模板匹配
							this.services = projectList.map(project => ({
								id: project.id,
								name: project.projectName || '',
								duration: project.duration || 60,
								price: project.price || 0,
								img: project.imgUrls ? project.imgUrls.split(',')[0] :
									'/static/default-service.jpg',
								originalPrice: project.originalPrice || project.price || 0
							}))
							this.projectList = res.data.rows || []
							console.log('加载所有项目成功:', this.services)

							// 如果有预选择的服务ID，自动选中该服务
							if (this.preSelectedServiceId) {
								const preSelectedService = this.services.find(service =>
									service.id.toString() === this.preSelectedServiceId.toString()
								)
								if (preSelectedService) {
									console.log('自动选中预选服务:', preSelectedService)
									this.selectService(preSelectedService)
								}
							}
						} else {
							console.error('获取项目列表失败:', res.data.msg)
						}
					},
					fail: (err) => {
						console.error('获取项目列表失败:', err)
					}
				})
			},
			// 根据技师技能分类加载对应的服务项目
			loadServicesByCategory(categoryIds) {
				if (!categoryIds) {
					// 如果没有分类ID，加载所有项目
					this.loadAllProjects()
					return
				}
				// 将分类ID字符串转换为数组
				const categoryIdArray = typeof categoryIds === 'string' ?
					categoryIds.split(',').filter(id => id.trim()) :
					categoryIds
				if (categoryIdArray.length === 0) {
					this.loadAllProjects()
					return
				}
				uni.request({
					url: `${uni.$config.baseUrl}/project/project/listByCategoryIds`,
					method: 'GET',
					data: {
						categoryIds: categoryIdArray.join(','),
						status: 1
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data && res.data.code === 200) {
							const projectList = res.data.rows || []
							// 处理项目数据格式，确保与页面模板匹配
							this.services = projectList.map(project => ({
								id: project.id,
								name: project.projectName || '',
								duration: project.duration || 60,
								price: project.price || 0,
								img: project.imgUrls ? project.imgUrls.split(',')[0] :
									'/static/default-service.jpg',
								originalPrice: project.originalPrice || project.price || 0
							}))
							this.projectList = res.data.rows || []
							// 如果有预选择的服务ID，自动选中该服务
							if (this.preSelectedServiceId) {
								const preSelectedService = this.services.find(service =>
									service.id.toString() === this.preSelectedServiceId.toString()
								)
								if (preSelectedService) {
									console.log('自动选中预选服务:', preSelectedService)
									this.selectService(preSelectedService)
								}
							}
							// 如果没有匹配的服务项目，显示提示
							if (this.services.length === 0) {
								uni.showToast({
									title: '该技师暂无可预约的服务项目',
									icon: 'none',
									duration: 2000
								})
								// 尝试加载所有项目作为备选
								this.loadAllProjects()
							}
						} else {
							// 如果请求失败，尝试加载所有项目
							this.loadAllProjects()
						}
					},
					fail: (err) => {
						// 如果请求失败，尝试加载所有项目
						this.loadAllProjects()
					}
				})
			},
			/**
			 * 处理H5环境中的微信支付
			 * @param {Object} payData 支付参数
			 * @param {String} orderId 订单ID
			 */
			callWechatH5Pay(payData, orderId) {
				if (typeof WeixinJSBridge === 'undefined') {
					document.addEventListener('WeixinJSBridgeReady', () => {
						this.onWeixinJSBridgeReady(payData, orderId);
					}, false);
					uni.showToast({
						title: '请在微信内完成支付',
						icon: 'none'
					});
					this.isSubmitting = false;
					return;
				}
				this.onWeixinJSBridgeReady(payData, orderId);
			},
			// WeixinJSBridge回调处理
			onWeixinJSBridgeReady(payData, orderId) {
				WeixinJSBridge.invoke(
					'getBrandWCPayRequest', {
						"appId": payData.appId,
						"timeStamp": payData.timeStamp,
						"nonceStr": payData.nonceStr,
						"package": payData.package,
						"signType": "RSA",
						"paySign": payData.paySign
					},
					(res) => {
						if (res.err_msg === "get_brand_wcpay_request:ok") {
							// 支付成功
							uni.showToast({
								title: '支付成功',
								icon: 'success',
								duration: 2000,
								success: () => {
									setTimeout(() => {
										uni.navigateTo({
											url: '/pages/my-orders/my-orders'
										})
									}, 2000)
								}
							});
							// 更新订单支付状态
							this.updateOrderPaymentStatus(orderId, 1);
						} else if (res.err_msg === "get_brand_wcpay_request:cancel") {
							// 用户取消支付
							uni.showToast({
								title: '支付已取消，可在全部订单中查看',
								icon: 'none'
							});
							this.isSubmitting = false;
						} else {
							// 支付失败
							uni.showToast({
								title: '支付失败',
								icon: 'none'
							});
							console.error('微信支付失败:', res.err_msg);
							this.isSubmitting = false;
						}
					}
				);
			},

			// 更新订单支付状态
			updateOrderPaymentStatus(orderId, paymentStatus) {
				if (!orderId) {
					console.error('订单ID不能为空')
					return
				}
				uni.request({
					url: `${uni.$config.baseUrl}/orders/orders/updatePaymentStatus`,
					method: 'POST',
					data: {
						orderId: orderId,
						paymentStatus: paymentStatus
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data.code === 200) {} else {}
					},
					fail: (err) => {}
				})
			},

			/**
			 * 小程序环境支付方法
			 * @param {Object} payData 支付参数
			 * @param {String} orderId 订单ID
			 */
			callWxPayment(payData, orderId) {
				uni.requestPayment({
					...payData,
					success: () => {
						uni.showToast({
							title: '支付成功',
							icon: 'success',
							duration: 2000,
							success: () => {
								setTimeout(() => {
									uni.navigateTo({
										url: '/pages/my-orders/my-orders'
									})
								}, 2000)
							}
						})
						// 更新订单支付状态
						this.updateOrderPaymentStatus(orderId, 1);
					},
					fail: (err) => {
						console.error('支付失败:', err)
						if (err.errMsg.indexOf('cancel') !== -1) {
							uni.showToast({
								title: '支付已取消，可在全部订单中查看',
								icon: 'none'
							})
						} else {
							uni.showToast({
								title: '支付失败',
								icon: 'none'
							})
						}
						this.isSubmitting = false
					},
					complete: () => {
						// 确保在任何情况下都重置提交状态
						this.isSubmitting = false
					}
				})
			},

			/**
			 * APP环境支付方法
			 * @param {Object} payData 支付参数
			 * @param {String} orderId 订单ID
			 */
			callAppPayment(payData, orderId) {
				plus.payment.getChannels(channels => {
					const wxChannel = channels.find(channel => channel.id === 'wxpay')
					if (wxChannel) {
						plus.payment.request(wxChannel, payData.paymentData, result => {
							uni.showToast({
								title: '支付成功',
								icon: 'success',
								duration: 2000,
								success: () => {
									setTimeout(() => {
										uni.navigateTo({
											url: '/pages/my-orders/my-orders'
										})
									}, 2000)
								}
							})
							// 更新订单支付状态
							this.updateOrderPaymentStatus(orderId, 1);
						}, err => {
							console.error('APP支付失败:', err)
							uni.showToast({
								title: '支付失败',
								icon: 'none'
							})
							this.isSubmitting = false
						})
					} else {
						uni.showModal({
							title: '支付提示',
							content: '当前环境不支持微信支付',
							showCancel: false,
							success: () => {
								this.isSubmitting = false
							}
						})
					}
				}, err => {
					console.error('获取支付通道失败:', err)
					uni.showToast({
						title: '支付初始化失败',
						icon: 'none'
					})
					this.isSubmitting = false
				})
			},

			// 解码腾讯地图坐标点
			decodePolyline(coors) {
				const points = [];
				let lat = 0;
				let lng = 0;

				for (let i = 0; i < coors.length; i++) {
					let coord = coors[i];
					let lat_change = coord >> 1;
					let lng_change = coord;

					if (lat_change & 1) {
						lat_change = ~lat_change;
					}
					if (lng_change & 1) {
						lng_change = ~lng_change;
					}

					lat += lat_change;
					lng += lng_change;

					points.push({
						latitude: lat / 100000,
						longitude: lng / 100000
					});
				}

				return points;
			},

			// 更新地图显示路线
			updateMapRoute(points) {
				// 创建路线
				this.polyline = [{
					points: points,
					color: '#2B87FF',
					width: 4,
					arrowLine: true,
					dottedLine: false
				}]
			},

			// 减少附赠项目次数
			decreaseGiftServiceTimes() {
				if (!this.selectedGiftId) {
					return;
				}

				uni.request({
					url: `${uni.$config.baseUrl}/cardgiftuser/cardgiftuser/decreaseTimes`,
					method: 'POST',
					data: {
						id: this.selectedGiftId,
						times: 1, // 每次减少1次
						memberId: this.getCurrentMemberId() // 使用统一方法获取memberId
					},
					success: (res) => {
						if (res.data.code === 200) {
							console.log('减少附赠项目次数成功:', this.selectedGiftId);
						} else {
							console.error('减少附赠项目次数失败:', res.data.msg);
						}
					},
					fail: (err) => {
						console.error('减少附赠项目次数请求失败:', err);
					}
				});
			},

			// 减少会员卡次数或金额
			decreaseCardTimes() {
				if (!this.selectedMemberCard || !this.selectedMemberCard.id) {
					return;
				}

				// 根据会员卡类型决定是减少次数还是减少金额
				if (this.selectedMemberCard.memberCard.cardType === 1) {
					// 充值卡类型，减少金额
					this.decreaseCardBalance();
				} else {
					// 次卡类型，减少次数
					this.decreaseCardTimesOnly();
				}
			},

			// 减少会员卡次数
			decreaseCardTimesOnly() {
				if (!this.selectedMemberCard || !this.selectedMemberCard.id) {
					return;
				}

				uni.request({
					url: `${uni.$config.baseUrl}/usercard/usercard/decreaseTimes`,
					method: 'POST',
					data: {
						id: this.selectedMemberCard.id,
						times: 1, // 每次减少1次
						memberId: this.getCurrentMemberId() // 使用统一方法获取memberId
					},
					success: (res) => {
						if (res.data.code === 200) {
							console.log('减少会员卡次数成功:', this.selectedMemberCard.id);
						} else {
							console.error('减少会员卡次数失败:', res.data.msg);
						}
					},
					fail: (err) => {
						console.error('减少会员卡次数请求失败:', err);
					}
				});
			},
			// 减少会员卡余额
			decreaseCardBalance() {
				if (!this.selectedMemberCard || !this.selectedMemberCard.id) {
					return;
				}
				// 获取已选择的服务信息
				const selectedServiceInfo = this.services.find(s => s.id === this.selectedService);
				if (!selectedServiceInfo) {
					return;
				}
				// 计算需要扣除的金额
				const deductAmount = selectedServiceInfo.price;
				uni.request({
					url: `${uni.$config.baseUrl}/usercard/usercard/decreaseBalance`,
					method: 'POST',
					data: {
						id: this.selectedMemberCard.id,
						amount: deductAmount, // 扣除服务价格
						memberId: this.getCurrentMemberId() // 使用统一方法获取memberId
					},
					success: (res) => {
						if (res.data.code === 200) {}
					}
				});
			},
			// 选择附赠项目
			selectGiftService(gift) {
				// 如果当前选中的就是这个附赠项目，则取消选择
				if (this.selectedGiftId === gift.id) {
					this.selectedGift = null
					this.selectedGiftId = null;
				} else {
					// 否则选中新的附赠项目
					this.selectedGiftId = gift.id;
					this.selectedGift = gift
				}
			},
			// 获取当前登录用户的memberId
			getCurrentMemberId() {
				const userInfoStr = uni.getStorageSync('userInfo')
				let userInfo = null
				if (userInfoStr) {
					try {
						// 如果是字符串，尝试解析
						if (typeof userInfoStr === 'string') {
							const parsed = JSON.parse(userInfoStr)
							// 检查是否是登录响应格式
							if (parsed.code === 200 && parsed.data) {
								userInfo = parsed.data
							} else {
								userInfo = parsed
							}
						} else {
							// 如果不是字符串，直接使用
							userInfo = userInfoStr
						}
					} catch (e) {
						console.error('解析用户信息失败', e)
						// 解析失败时，尝试直接使用
						userInfo = userInfoStr
					}
				}

				return userInfo ? userInfo.memberId : null
			},

			// 检查是否还有未选择的项
			checkUnselectedTips() {
				const hasUnselected = !this.selectedService ||
					!this.selectedDate ||
					!this.selectedTime ||
					!this.selectedAddress

				this.showUnselectedTips = hasUnselected

				// 如果所有项都已选择，确保提示完全隐藏
				if (!hasUnselected) {
					this.$nextTick(() => {
						this.showUnselectedTips = false
					})
				}
			},

			// 滚动到服务项目
			scrollToService() {
				uni.pageScrollTo({
					selector: '.service-list',
					duration: 300
				})
			},

			// 滚动到时间选择
			scrollToTime() {
				uni.pageScrollTo({
					selector: '.time-select',
					duration: 300
				})
			},

			// 滚动到地址选择
			scrollToAddress() {
				uni.pageScrollTo({
					selector: '.address-select',
					duration: 300
				})
			},

			// 加载附加项目列表
			loadAdditionalServices() {
				uni.request({
					url: `${uni.$config.baseUrl}/project/project/listAll`,
					method: 'GET',
					data: {
						status: 1
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data && res.data.code === 200) {
							// 筛选出艾灸、刮痧、拔罐三个项目
							const targetServices = ['艾灸', '刮痧', '拔罐']
							this.additionalServiceList = res.data.rows.filter(project =>
								targetServices.includes(project.projectName)
							)

							// 创建项目映射
							this.additionalServiceList.forEach(service => {
								this.additionalServicesMap[service.id] = service
							})
						}
					}
				})
			},

			// 切换附加项目选择状态
			toggleAdditionalService(service) {
				const index = this.selectedAdditionalServices.indexOf(service.id)
				if (index === -1) {
					this.selectedAdditionalServices.push(service.id)
				} else {
					this.selectedAdditionalServices.splice(index, 1)
				}
				this.calculateTotalPrice() // 重新计算总价
			},

			// 根据项目ID获取项目名称
			getProjectName(projectId) {
				const project = this.projectList.find(p => p.id === projectId)
				return project ? project.projectName : '未知项目'
			},

			// 调用后端接口获取时间段
			fetchAvailableTimes(dateObj) {
				this.selectedDate = dateObj.value
				this.selectedTime = ''
				this.availableTimes = []

				// 没选技师或服务时回退
				if (!this.techInfo.id || !this.currentService || !this.currentService.duration) {
					this.updateAvailableTimes()
					return
				}

				uni.request({
					url: `${uni.$config.baseUrl}/servicetime/servicetime/get-server-time-list`,
					method: 'POST',
					header: {
						'content-type': 'application/json'
					},
					data: {
						date: dateObj.value,
						techId: this.techInfo.id,
						duration: this.currentService.duration,
					},
					success: (res) => {
						if (res.statusCode === 200 && res.data.code === 200) {
							const raw = res.data.data || []
							this.availableTimes = raw.map(item => ({
								label: item.timePoint,
								value: item.timePoint,
								key: `${dateObj.value}_${item.timePoint}`,
								disabled: !!item.disabled
							}))
						} else {
							// 接口失败保持空列表，等待用户重新选择
						}
					},
					fail: () => {
						// 网络失败，不展示默认时间
					}
				})
			},
			// 根据技师 ID 精准加载项目
			loadServicesByTechnician(techId) {
				if (!techId) {
					this.services = []
					return
				}
				uni.request({
					url: `${uni.$config.baseUrl}/project/project/technician/${techId}`,
					method: 'GET',
					success: (res) => {
						if (res.statusCode === 200 && res.data.code === 200) {
							const list = res.data.rows || []
							this.services = list.map(p => ({
								id: p.id,
								name: p.projectName,
								duration: p.duration || 60,
								price: p.price || 0,
								img: p.imgUrls ? p.imgUrls.split(',')[0] :
									'/static/default-service.jpg',
								originalPrice: p.originalPrice || p.price || 0
							}))
							this.projectList = list

							// 预选服务
							if (this.preSelectedServiceId) {
								const pre = this.services.find(s => s.id.toString() === this
									.preSelectedServiceId.toString())
								if (pre) this.selectService(pre)
							}
							if (this.services.length === 0) {
								uni.showToast({
									title: '该技师暂无可预约项目',
									icon: 'none'
								})
							}
						} else {
							this.services = []
						}
					},
					fail: () => {
						this.services = []
					}
				})
			},
		},
		computed: {
			sortedAddressList() {
				return [...this.addressList].sort((a, b) => {
					// Sort by isDefault (1 first, then 0)
					return (b.isDefault || 0) - (a.isDefault || 0);
				});
			}
		}
	}
</script>

<style lang="scss">
	.tech-detail {
		background: #F8F8F8;
		min-height: 100vh;
		padding-bottom: calc(140rpx + env(safe-area-inset-bottom)); // 为底部结算栏预留空间

		.tech-info {
			background: #FFFFFF;
			padding: 40rpx;
			display: flex;
			align-items: center;

			.avatar {
				width: 120rpx;
				height: 120rpx;
				border-radius: 60rpx;
				margin-right: 30rpx;
			}

			.info {
				flex: 1;

				.name {
					font-size: 32rpx;
					color: #333;
					font-weight: 500;
					margin-bottom: 16rpx;
				}

				.rating {
					margin-bottom: 12rpx;
					font-size: 24rpx;

					.score {
						color: #FF9500;
						margin-right: 30rpx;
					}

					.orders {
						color: #666;
					}
				}

				.desc {
					font-size: 24rpx;
					color: #666;
				}
			}

			.info-icon {
				font-size: 40rpx;
				color: #999;
				padding: 10rpx;
			}
		}

		.location-info {
			background: #FFFFFF;
			margin-top: 24rpx;
			padding: 40rpx;

			.map-container {
				height: 300rpx;
				border-radius: 12rpx;
				overflow: hidden;

				.map {
					width: 100%;
					height: 100%;
				}
			}

			.distance-info {
				display: flex;
				justify-content: space-between;
				padding: 30rpx 0 10rpx;
				font-size: 26rpx;
				color: #666;
			}
		}

		.module-title {
			font-size: 32rpx;
			font-weight: 600;
			color: #333;
			margin-bottom: 20rpx;
			display: flex;
			justify-content: space-between;
			align-items: center;

			.scroll-hint {
				font-size: 32rpx; // 从24rpx改为28rpx
				color: #2B87FF;
				opacity: 0.8;
			}
		}

		.service-list {
			background: #FFFFFF;
			padding: 40rpx 40rpx 20rpx;
			margin-top: 24rpx;
			height: 600rpx;

			.service-scroll {
				height: 100%;
				padding-right: 10rpx;
				overflow-y: scroll;

				&::-webkit-scrollbar {
					width: 6rpx;
					background-color: #F8F8F8;
				}

				&::-webkit-scrollbar-thumb {
					background-color: #DDDDDD;
					border-radius: 3rpx;
				}
			}

			.service-item {
				position: relative;
				display: flex;
				align-items: center;
				padding: 30rpx;
				border-bottom: 2rpx solid #F5F5F5;
				transition: all 0.3s ease;

				&:last-child {
					border-bottom: none;
				}

				.service-image {
					width: 160rpx;
					height: 160rpx;
					border-radius: 12rpx;
					margin-right: 30rpx;
					flex-shrink: 0;
					object-fit: cover;
					box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
				}

				.service-content {
					flex: 1;
					min-width: 0;

					.service-info {
						margin-bottom: 16rpx;

						.name {
							font-size: 32rpx;
							color: #333;
							font-weight: 500;
							margin-bottom: 12rpx;
							display: block;
						}

						.duration {
							font-size: 26rpx;
							color: #999;
							display: block;
							position: relative;
							padding-left: 32rpx;

							&::before {
								content: '⏱';
								position: absolute;
								left: 0;
								top: 50%;
								transform: translateY(-50%);
								font-size: 24rpx;
								line-height: 24rpx;
								color: #999;
							}
						}
					}

					.price-info {
						text-align: right;

						.price {
							font-size: 36rpx;
							color: #2B87FF;
							font-weight: 600;
							margin-bottom: 8rpx;
							display: block;
						}

						.original-price {
							font-size: 24rpx;
							color: #999;
							text-decoration: line-through;
						}
					}
				}

				&.active {
					background: rgba(43, 135, 255, 0.05);

					.name {
						color: #2B87FF;
					}

					.duration {
						color: rgba(43, 135, 255, 0.7);

						&::before {
							color: rgba(43, 135, 255, 0.7);
						}
					}

					.price {
						color: #2B87FF;
					}
				}

				&:active {
					transform: scale(0.98);
					opacity: 0.9;
				}
			}
		}

		.time-select {
			background: #FFFFFF;
			padding: 40rpx 40rpx 20rpx;
			margin-top: 24rpx;

			.date-list {
				display: flex;
				margin-bottom: 40rpx;

				.date-item {
					flex: 1;
					padding: 24rpx 20rpx;
					text-align: center;
					border: 1rpx solid #EEEEEE;
					border-radius: 8rpx;
					margin: 0 15rpx;
					transition: all 0.3s ease;

					.day {
						font-size: 28rpx;
						color: #333;
						margin-bottom: 12rpx;
						display: block;
					}

					.date {
						font-size: 24rpx;
						color: #666;
					}

					&.active {
						background: #2B87FF;
						border-color: #2B87FF;
						transform: translateY(-2rpx);
						box-shadow: 0 4rpx 12rpx rgba(43, 135, 255, 0.2);

						.day,
						.date {
							color: #FFFFFF;
						}
					}
				}
			}

			.time-list {
				height: 360rpx;
				padding-right: 10rpx;
				overflow-y: scroll;

				&::-webkit-scrollbar {
					width: 6rpx;
					background-color: #F8F8F8;
				}

				&::-webkit-scrollbar-thumb {
					background-color: #DDDDDD;
					border-radius: 3rpx;
				}

				.time-grid {
					display: grid;
					grid-template-columns: repeat(3, 1fr);
					gap: 16rpx;
					padding: 8rpx 4rpx;

					.time-item {
						background: #F8F8F8;
						border-radius: 8rpx;
						display: flex;
						flex-direction: column;
						align-items: center;
						justify-content: center;
						padding: 16rpx 8rpx;
						min-height: 100rpx;

						.time-text {
							font-size: 28rpx;
							color: #333;
							margin-bottom: 4rpx;
						}

						.duration-text {
							font-size: 22rpx;
							color: #666;
							text-align: center;
							white-space: nowrap;
							padding: 0 8rpx;
						}

						&.active {
							background: #2B87FF;

							.time-text,
							.duration-text {
								color: #FFFFFF;
							}
						}

						&.disabled {
							background: #EEEEEE;

							.time-text,
							.duration-text {
								color: #999999;
							}
						}
					}
				}
			}
		}

		.transport-select {
			background: #FFFFFF;
			padding: 40rpx;
			margin-top: 24rpx;

			.transport-list {
				display: flex;
				gap: 20rpx;

				.transport-item {
					flex: 1;
					height: 140rpx;
					border: 2rpx solid #EEEEEE;
					border-radius: 12rpx;
					display: flex;
					flex-direction: column;
					align-items: center;
					justify-content: center;
					position: relative;
					transition: all 0.3s ease;

					.name {
						font-size: 26rpx;
						color: #333;
						margin-bottom: 8rpx;
						margin-top: 8rpx;
					}

					.price {
						font-size: 24rpx;
						color: #2B87FF;
					}

					&.active {
						background: rgba(43, 135, 255, 0.05);
						border-color: #2B87FF;
						transform: translateY(-2rpx);
						box-shadow: 0 4rpx 12rpx rgba(43, 135, 255, 0.1);

						.name {
							color: #2B87FF;
						}

						.price {
							color: #2B87FF;
							font-weight: 500;
						}
					}

					&:active {
						transform: scale(0.98);
						opacity: 0.9;
					}
				}
			}
		}

		.address-select {
			background: #FFFFFF;
			padding: 40rpx;
			margin-top: 24rpx;
			margin-bottom: 24rpx; // 添加底部间距

			.address-input {
				display: flex;
				align-items: center;
				justify-content: space-between;
				padding: 30rpx;
				background: #F8F8F8;
				border-radius: 12rpx;

				.input-content {
					font-size: 28rpx;
					color: #333;

					&.placeholder {
						color: #999;
					}
				}

				.arrow {
					font-size: 28rpx;
					color: #999;
					transform: rotate(90deg);
				}
			}
		}

		.address-popup {
			position: fixed;
			left: 0;
			right: 0;
			bottom: 0;
			background: #FFFFFF;
			border-radius: 24rpx 24rpx 0 0;
			transform: translateY(100%);
			transition: transform 0.3s ease;
			z-index: 1001;

			&.show {
				transform: translateY(0);
			}

			.popup-header {
				display: flex;
				align-items: center;
				justify-content: space-between;
				padding: 30rpx;
				border-bottom: 1rpx solid #EEEEEE;

				.title {
					font-size: 32rpx;
					color: #333;
					font-weight: 500;
				}

				.header-right {
					display: flex;
					align-items: center;

					.manage {
						font-size: 28rpx;
						color: #2B87FF;
						margin-right: 30rpx;
					}

					.close {
						font-size: 40rpx;
						color: #999;
						padding: 10rpx;
					}
				}
			}

			.address-list {
				padding: 20rpx 0;
				max-height: 60vh;
				overflow-y: auto;

				.address-item {
					position: relative;
					padding: 30rpx 40rpx;
					border-bottom: 1rpx solid #EEEEEE;
					transition: all 0.3s ease;

					&:last-child {
						border-bottom: none;
					}

					.address-info {
						display: flex;
						justify-content: space-between;
						align-items: center;
						margin-bottom: 10rpx;

						.left-info {
							display: flex;
							align-items: center;

							.name {
								font-size: 28rpx;
								color: #333;
								margin-right: 20rpx;
							}

							.phone {
								font-size: 26rpx;
								color: #666;
							}
						}

						.right-info {
							display: flex;
							align-items: center;
							gap: 10rpx;

							.tag {
								font-size: 24rpx;
								color: #2B87FF;
								background: rgba(43, 135, 255, 0.1);
								padding: 4rpx 12rpx;
								border-radius: 4rpx;
							}

							.default-tag {
								font-size: 24rpx;
								color: #FF6B35;
								background: rgba(255, 107, 53, 0.1);
								padding: 4rpx 12rpx;
								border-radius: 4rpx;
							}
						}
					}

					.address {
						font-size: 26rpx;
						color: #666;
						line-height: 1.4;
					}

					.select-icon {
						position: absolute;
						right: 30rpx;
						top: 50%;
						transform: translateY(-50%);
						font-size: 40rpx;
						color: #2B87FF;
					}

					&.active {
						background: #F8F8F8;

						.name {
							color: #2B87FF;
						}
					}

					&:active {
						transform: scale(0.98);
						opacity: 0.9;
					}
				}
			}
		}

		.mask {
			position: fixed;
			left: 0;
			right: 0;
			top: 0;
			bottom: 0;
			background: rgba(0, 0, 0, 0.3);
			z-index: 1000;
		}

		.settlement {
			height: 7%;
			position: fixed;
			left: 0;
			right: 0;
			bottom: 0;
			background: #FFFFFF;
			display: flex;
			align-items: center;
			justify-content: space-between;
			box-shadow: 0 -2rpx 20rpx rgba(0, 0, 0, 0.05);
			z-index: 99; // 确保在正常内容之上，但在弹窗之下

			.price-info {
				margin-left: 4%;

				.label {
					font-size: 28rpx;
					color: #666;
					margin-right: 20rpx;
				}

				.price {
					font-size: 36rpx;
					color: #FF6B6B;
					font-weight: 600;
				}
			}

			.submit-btn {
				background: #2B87FF;
				color: #FFFFFF;
				font-size: 32rpx;
				border-radius: 40rpx;
				border: none;

				&:active {
					opacity: 0.9;
					transform: scale(0.98);
				}

				&.disabled {
					background: linear-gradient(135deg, #AAAAAA 0%, #999999 100%);
					opacity: 0.8;
					pointer-events: none;
				}
			}
		}

		.remark-section {
			background: #FFFFFF;
			padding: 40rpx;
			margin-top: 24rpx;
			margin-bottom: 24rpx;

			.remark-input {
				position: relative;
				background: #F8F8F8;
				border-radius: 12rpx;
				padding: 20rpx;

				textarea {
					width: 100%;
					height: 160rpx;
					font-size: 28rpx;
					color: #333;
					line-height: 1.5;

					&::placeholder {
						color: #999;
					}
				}

				.word-count {
					position: absolute;
					right: 20rpx;
					bottom: 20rpx;
					font-size: 24rpx;
					color: #999;
				}
			}
		}

		.mini-confirm-dialog {
			position: fixed;
			left: 0;
			right: 0;
			top: 0;
			bottom: 0;
			z-index: 1000;
			display: flex;
			align-items: center;
			justify-content: center;

			.dialog-mask {
				position: absolute;
				left: 0;
				right: 0;
				top: 0;
				bottom: 0;
				background: rgba(0, 0, 0, 0.5);
				z-index: 1001;
			}

			.dialog-content {
				position: relative;
				width: 560rpx;
				background: #FFFFFF;
				border-radius: 24rpx;
				padding: 40rpx;
				z-index: 1002;
				animation: scaleIn 0.3s ease;

				.dialog-title {
					font-size: 32rpx;
					color: #333;
					font-weight: 500;
					text-align: center;
					margin-bottom: 20rpx;
				}

				.dialog-text {
					font-size: 28rpx;
					color: #666;
					text-align: center;
					margin-bottom: 20rpx;
				}

				.dialog-price {
					font-size: 40rpx;
					color: #2B87FF;
					font-weight: bold;
					text-align: center;
					margin-bottom: 30rpx;
				}

				.dialog-buttons {
					display: flex;
					gap: 20rpx;

					button {
						flex: 1;
						height: 80rpx;
						border-radius: 40rpx;
						font-size: 28rpx;
						display: flex;
						align-items: center;
						justify-content: center;

						&.cancel-btn {
							background: #F5F5F5;
							color: #666;
						}

						&.confirm-btn {
							background: #2B87FF;
							color: #FFFFFF;
						}

						&:active {
							opacity: 0.9;
							transform: scale(0.98);
						}
					}
				}
			}

			@keyframes scaleIn {
				from {
					transform: scale(0.8);
					opacity: 0;
				}

				to {
					transform: scale(1);
					opacity: 1;
				}
			}

		}

		.coupon-section {
			background: #FFFFFF;
			padding: 40rpx;
			margin-top: 24rpx;
			margin-bottom: 24rpx;

			.coupon-list {
				.coupon-item {
					display: flex;
					justify-content: space-between;
					align-items: center;
					padding: 30rpx;
					background: #F8F8F8;
					border-radius: 12rpx;
					margin-bottom: 20rpx;
					border: 2rpx solid transparent;
					transition: all 0.3s ease;

					&:last-child {
						margin-bottom: 0;
					}

					&.active {
						background: rgba(43, 135, 255, 0.05);
						border-color: #2B87FF;
					}

					.coupon-info {
						flex: 1;

						.coupon-name {
							font-size: 28rpx;
							color: #333;
							font-weight: 500;
							margin-bottom: 8rpx;
						}

						.coupon-desc {
							font-size: 24rpx;
							color: #666;
							margin-bottom: 8rpx;
						}

						.coupon-validity {
							font-size: 22rpx;
							color: #999;
						}
					}

					.coupon-amount {
						text-align: right;

						.amount {
							font-size: 36rpx;
							color: #FF6B35;
							font-weight: bold;
							display: block;
							margin-bottom: 8rpx;
						}

						.condition {
							font-size: 22rpx;
							color: #999;
						}
					}
				}

				.no-coupon {
					text-align: center;
					padding: 40rpx;
					color: #999;
					font-size: 28rpx;
				}
			}
		}

		.member-card-section {
			background: #FFFFFF;
			padding: 40rpx;
			margin-top: 24rpx;
			margin-bottom: 24rpx;

			.member-card-list {
				.member-card-item {
					display: flex;
					justify-content: space-between;
					align-items: center;
					padding: 30rpx;
					background: #F8F8F8;
					border-radius: 12rpx;
					margin-bottom: 20rpx;
					border: 2rpx solid transparent;
					transition: all 0.3s ease;

					&:last-child {
						margin-bottom: 0;
					}

					&.active {
						background: rgba(43, 135, 255, 0.05);
						border-color: #2B87FF;
					}

					&.disabled {
						opacity: 0.6;
						background: #f5f5f5;
						pointer-events: none;
					}

					.card-info {
						flex: 1;

						.card-name {
							font-size: 28rpx;
							color: #333;
							font-weight: 500;
							margin-bottom: 8rpx;

							&.disabled {
								color: #999;
							}
						}

						.card-desc {
							font-size: 24rpx;
							color: #666;
							margin-bottom: 8rpx;

							&.disabled {
								color: #999;
							}
						}

						.card-validity {
							font-size: 22rpx;
							color: #999;

							&.disabled {
								color: #bbb;
							}
						}
					}

					.card-action {
						.action-text {
							font-size: 26rpx;
							color: #2B87FF;
							background: rgba(43, 135, 255, 0.1);
							padding: 8rpx 24rpx;
							border-radius: 24rpx;

							&.disabled {
								color: #999;
								background: #eee;
							}
						}
					}
				}

				.no-card {
					text-align: center;
					padding: 40rpx;
					color: #999;
					font-size: 28rpx;
				}
			}
		}

		.gift-service-list {
			background: #FFFFFF;
			padding: 40rpx;
			margin-top: 24rpx;

			.gift-item {
				display: flex;
				flex-direction: column;
				background: #fff;
				border-radius: 12rpx;
				padding: 24rpx;
				margin-bottom: 20rpx;
				position: relative;

				&.disabled {
					opacity: 0.6;
					background: #f5f5f5;
					pointer-events: none;
				}

				&.active {
					background: #f8f8f8;
					border: 2rpx solid #007AFF;
				}
			}

			.gift-info {
				display: flex;
				align-items: center;
				margin-bottom: 16rpx;

				.times {
					font-size: 26rpx;
					color: #666;
					margin-right: 20rpx;
					background: rgba(43, 135, 255, 0.1);
					padding: 4rpx 12rpx;
					border-radius: 4rpx;

					&.disabled {
						background: #eee;
						color: #999;
					}
				}

				.name {
					font-size: 28rpx;
					color: #333;
					font-weight: 500;
					flex: 1;

					&.disabled {
						color: #999;
					}
				}
			}

			.validity {
				font-size: 24rpx;
				color: #999;

				.disabled {
					color: #bbb;
				}
			}

			.gift-action {
				position: absolute;
				right: 24rpx;
				top: 50%;
				transform: translateY(-50%);

				.action-text {
					font-size: 26rpx;
					color: #007AFF;
					padding: 8rpx 24rpx;
					background: rgba(0, 122, 255, 0.1);
					border-radius: 30rpx;

					&.disabled {
						color: #999;
						background: #eee;
					}
				}
			}
		}

		// 交通费用显示
		.transport-fee {
			background: #FFFFFF;
			padding: 40rpx;
			margin-top: 24rpx;

			.fee-display {
				display: flex;
				justify-content: space-between;
				align-items: center;

				.fee-label {
					font-size: 28rpx;
					color: #666;
				}

				.fee-amount {
					font-size: 36rpx;
					color: #2B87FF;
					font-weight: 600;
				}
			}
		}

		.unselected-tips {
			position: fixed;
			right: 30rpx;
			top: 120rpx;
			background: rgba(0, 0, 0, 0.7);
			padding: 20rpx;
			border-radius: 12rpx;
			z-index: 100;

			.tips-item {
				display: flex;
				align-items: center;
				padding: 12rpx 20rpx;
				font-size: 26rpx;
				color: #FFFFFF;
				white-space: nowrap;

				.icon {
					color: #FF6B35;
					margin-right: 12rpx;
					font-size: 24rpx;
				}

				.jump-text {
					margin-left: 20rpx;
					font-size: 24rpx;
					color: #2B87FF;
				}

				&:active {
					opacity: 0.8;
				}
			}
		}

		.additional-services {
			background: #FFFFFF;
			padding: 40rpx;
			margin-top: 24rpx;

			.service-options {
				display: flex;
				flex-wrap: wrap;
				gap: 20rpx;

				.service-option {
					flex: 1;
					min-width: 200rpx;
					padding: 20rpx;
					background: #F8F8F8;
					border-radius: 12rpx;
					display: flex;
					flex-direction: column;
					align-items: center;
					border: 2rpx solid transparent;
					transition: all 0.3s ease;

					.service-name {
						font-size: 28rpx;
						color: #333;
						margin-bottom: 8rpx;
					}

					.service-price {
						font-size: 24rpx;
						color: #666;
					}

					&.active {
						background: rgba(43, 135, 255, 0.05);
						border-color: #2B87FF;

						.service-name {
							color: #2B87FF;
						}

						.service-price {
							color: #2B87FF;
						}
					}

					&:active {
						transform: scale(0.98);
						opacity: 0.9;
					}
				}
			}
		}
	}
</style>